#include "app_buffer.h"
#include "log.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

Buffer *app_buffer_init(int total_size)
{
    // 1.创建大缓冲区 开辟内存
    Buffer *buffer = (Buffer *)malloc(sizeof(Buffer));

    // 2.创建小缓冲区 开辟内存 创建两个，每个有单独的存储空间大小，数据长度
    for (int i = 0; i < 2; i++)
    {
        SubBuffer *sub_buffer = (SubBuffer *)malloc(sizeof(SubBuffer));
        sub_buffer->ptr = (char *)malloc(total_size);
        sub_buffer->total_size = total_size;
        sub_buffer->len = 0;
        buffer->sub_buffers[i] = sub_buffer;
    }

    // 3.指定哪个为读，哪个为写
    buffer->read_index = 0;
    buffer->write_index = 1;

    // 4.锁初始化
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->swap_lock, NULL);

    return buffer;
}

int app_buffer_write(Buffer *buffer, char *write_data, int write_len)
{
    log_info("缓冲区写入开始，加锁...");
    int ret = pthread_mutex_lock(&buffer->swap_lock);
    if (ret < 0)
    {
        perror("缓冲区写入加锁失败！");
        return -1;
    }

    log_info("缓冲区写入加锁成功，开始写入...");
    // 1.获取写缓冲区
    SubBuffer *write_sub_buffer = buffer->sub_buffers[buffer->write_index];

    // 2.校验长度是否足够写入
    if (write_len > write_sub_buffer->total_size - write_sub_buffer->len)
    {
        log_error("待写入长度超过缓冲区剩余长度");
        pthread_mutex_unlock(&buffer->swap_lock);
        return -1;
    }

    // 3.写入数据 + 长度增加
    memcpy(write_sub_buffer->ptr + write_sub_buffer->len, write_data, write_len);
    write_sub_buffer->len += write_len;

    pthread_mutex_unlock(&buffer->swap_lock);

    return 0;
}

int app_buffer_read(Buffer *buffer, char *read_buff, int read_buff_size)
{
    // 此处加锁，因为下面的操作涉及到了公共数据
    pthread_mutex_lock(&buffer->read_lock);
    // 1.获取读缓冲区
    SubBuffer *read_sub_buffer = buffer->sub_buffers[buffer->read_index];

    // 2.获取在当前读缓冲区可读的长度（从可用空间和当前读缓冲区已有数据 取较小值）
    int real_read_size = read_sub_buffer->len < read_buff_size ? read_sub_buffer->len : read_buff_size;

    // 3.进行读取数据 1>读取数据到目标空间 2>用后面的数据覆盖掉前面的数据 3>长度减少
    if (real_read_size > 0)
    {
        memcpy(read_buff, read_sub_buffer->ptr, real_read_size);
        memmove(read_sub_buffer->ptr, read_sub_buffer->ptr + real_read_size, read_sub_buffer->len - real_read_size);
        read_sub_buffer->len -= real_read_size;
    }

    // 4.只要读缓冲区可读的长度为0,进行读写缓冲区切换
    if (read_sub_buffer->len == 0)
    {
        pthread_mutex_lock(&buffer->swap_lock);
        // 读写下标号的交换
        int tmp_index = buffer->read_index;
        buffer->read_index = buffer->write_index;
        buffer->write_index = tmp_index;
        pthread_mutex_unlock(&buffer->swap_lock);

        // 5.获取新的读缓冲区
        read_sub_buffer = buffer->sub_buffers[buffer->read_index];

        // 6.再次获取在当前读缓冲区可读的长度（从剩余可用空间和当前读缓冲区已有数据 取较小值）
        int remain_read_buff_size = read_buff_size - real_read_size;
        int swaped_real_read_size = read_sub_buffer->len < remain_read_buff_size ? read_sub_buffer->len : remain_read_buff_size;

        // 7.再次读取数据
        if (swaped_real_read_size > 0)
        {
            // 1>读取数据到目标空间 2>用后面的数据覆盖掉前面的数据 3>长度减少
            memcpy(read_buff + real_read_size, read_sub_buffer->ptr, swaped_real_read_size);
            memmove(read_sub_buffer->ptr, read_sub_buffer->ptr + swaped_real_read_size, read_sub_buffer->len - swaped_real_read_size);
            read_sub_buffer->len -= swaped_real_read_size;
            // 实际读取的数据量 + 切换后读取的长度
            real_read_size += swaped_real_read_size;
        }
    }

    pthread_mutex_unlock(&buffer->read_lock);
    // 7.返回最终实际读取的数据量
    return real_read_size;
}

void app_buffer_free(Buffer *buffer)
{
    // 1.释放所有子缓冲区的数据空间
    free(buffer->sub_buffers[0]->ptr);
    free(buffer->sub_buffers[1]->ptr);
    // 2.释放所有子缓冲区结构体空间
    free(buffer->sub_buffers[0]);
    free(buffer->sub_buffers[1]);
    // 3.释放主缓冲区结构体空间
    free(buffer);
}
